import config from '@/config';

interface ListenPendingAjax {
  [key: string]: boolean | UniNamespace.RequestTask;
}

// 记录正在请求的接口
let listenPendingAjax: ListenPendingAjax = {}; // 对应字段为true说明已有该请求，还未结束

function dialog(content: string): void {
  uni.showModal({
    title: '系统繁忙，请稍候再试',
    content,
    showCancel: false,
  });
}

/**
 * 请求拦截
 * @param options
 * @param requestTask
 * @returns
 */
function requestInterceptor(options: UniNamespace.RequestOptions): RequestErrorResult {
  if (listenPendingAjax[options.url]) {
    // 存储路径为完整路径
    // 拦截重复请求，为false时不做处理
    return {
      success: false,
      errMsg: '重复请求！',
    };
  }
  return {
    success: true,
    errMsg: '',
  };
}

/**
 * 请求成功的回调
 * @param response
 * @param options
 */
function responseSuccessCallback(response: UniNamespace.RequestSuccessCallbackResult, options: UniNamespace.RequestOptions) {
  if (options.url) {
    delete listenPendingAjax[options.url];
  } else {
    // 发生未知错误，一般不会执行进来
    listenPendingAjax = {};
    console.log('发生未知错误：', response);
  }
}

/**
 * 请求错误的回调
 * @param error
 * @param options
 * @returns
 */
function responseErrorCallback(error: UniNamespace.GeneralCallbackResult, options: UniNamespace.RequestOptions) {
  if (options.url && typeof options.url === 'string') {
    delete listenPendingAjax[options.url];
  } else {
    // 可能是网络错误，清空记录，防止下一次请求被拦截
    listenPendingAjax = {};
  }
  if (error.errMsg === 'ECONNABORTED') {
    return '系统繁忙，请稍候再试';
  }
  if (/timeout/i.test(error.errMsg)) {
    return '系统超时，请稍候再试';
  }
  if (error.errMsg === 'Network Error') {
    return '网络错误，请检查网络情况';
  }
  return error.errMsg;
}

export default class Request {
  modulePath: string;

  constructor(modulePath: string) {
    this.modulePath = modulePath;
  }

  /**
   * 获取模块路径
   * @param url
   * @returns
   */
  getModuleUrl(url: string): string {
    return /^https?:\/\//.test(url) ? url : this.modulePath + url;
  }

  /**
   * 获取完整的url地址
   * @param url
   */
  getFullUrl(url: string): string {
    const _url = this.getModuleUrl(url);
    if (/^https?:\/\//.test(_url)) {
      return _url;
    } else {
      return /^https?:\/\//.test(config.requestBaseUrl) ? config.requestBaseUrl + _url : window.location.protocol + '//' + window.location.host + config.requestBaseUrl + _url;
    }
  }

  /**
   * 接口请求
   * @param options
   * @returns
   */
  request(options: UniNamespace.RequestOptions): Promise<UniApp.RequestSuccessCallbackResult> {
    return new Promise((resolve, reject) => {
      // 合并设置
      const _options = {
        timeout: config.requestTimeout,
        ...options,
        url: this.getFullUrl(options.url),
      };
      const interceptorRes: RequestErrorResult = requestInterceptor(_options);
      if (!interceptorRes.success) {
        reject(interceptorRes);
        return;
      }
      const requestTask = uni.request({
        ..._options,
        success: (res: UniApp.RequestSuccessCallbackResult) => {
          responseSuccessCallback(res, _options);
          options.success && options.success(res);
          resolve(res);
        },
        fail: (error: UniNamespace.GeneralCallbackResult) => {
          console.log(options.url, error);
          responseErrorCallback(error, _options);
          options.fail && options.fail(error);
          reject({
            success: false,
            errMsg: error.errMsg,
          });
          dialog(error.errMsg);
        },
      });
      if (listenPendingAjax[_options.url] !== false) {
        // 添加进接口记录
        listenPendingAjax[_options.url] = requestTask;
      }
    });
  }

  /**
   * get请求
   * @param url
   * @param option
   * @returns
   */
  get(url: string, options: UniNamespace.RequestOptions): Promise<UniApp.RequestSuccessCallbackResult> {
    return this.request({
      ...options,
      method: 'GET',
      url,
    });
  }

  /**
   * post请求
   * @param url
   * @param options
   * @returns
   */
  post(url: string, options: UniNamespace.RequestOptions): Promise<UniApp.RequestSuccessCallbackResult> {
    return this.request({
      ...options,
      method: 'POST',
      url,
    });
  }

  /**
   * put请求
   * @param url
   * @param options
   * @returns
   */
  put(url: string, options: UniNamespace.RequestOptions): Promise<UniApp.RequestSuccessCallbackResult> {
    return this.request({
      ...options,
      method: 'PUT',
      url,
    });
  }

  /**
   * delete请求
   * @param url
   * @param options
   * @returns
   */
  delete(url: string, options: UniNamespace.RequestOptions): Promise<UniApp.RequestSuccessCallbackResult> {
    return this.request({
      ...options,
      method: 'DELETE',
      url,
    });
  }

  /**
   * head请求
   * @param url
   * @param options
   * @returns
   */
  head(url: string, options: UniNamespace.RequestOptions): Promise<UniApp.RequestSuccessCallbackResult> {
    return this.request({
      ...options,
      method: 'HEAD',
      url,
    });
  }

  /**
   * 解除重复请求锁定，可以多次请求，解除可能会出现数据展示错乱的情况
   * @param url{string}
   * @returns {ServerRequest}
   */
  unlock(url: string): Request {
    listenPendingAjax[this.getFullUrl(url)] = false;
    return this;
  }

  /**
   * 取消请求
   * @param url
   * @returns
   */
  cancel(url: string): Request {
    const resUrl = this.getFullUrl(url);
    if (listenPendingAjax[resUrl]) {
      (listenPendingAjax[resUrl] as UniNamespace.RequestTask).abort();
      delete listenPendingAjax[resUrl];
    }
    return this;
  }
}
